#!/usr/bin/env python

import sys
import time
import logging
import traceback
from ConfigParser import ConfigParser

try:
    import gtk
    import dbus
    import getopt
    import pynotify
except ImportError:
    raise
    sys.exit(-1)



def usage(prog):
    print "\n\
    ========================================================\n\
             _     _                                        \n\
             \`\ /`/                                        \n\
              \ V /           - battepy -                   \n\
              /. .\                                         \n\
             =\ T /=    battery meter in python             \n\
              /   \                                         \n\
             /\\\\ //\                                      \n\
           __\ \" \" /__       { Ricardo Ichizo }           \n\
          (____/^\____)  { n1ghtcr4wler at gmail.com }      \n\
                                                            \n\
    ========================================================\n\
                                                            \n\
    Usage: %s <options>                                     \n\
                                                            \n\
      Options:                                              \n\
               -l [logfile]   :log into file (be daemon)    \n\
               -v             :be verbose                   \n\
               -h             :show this help               \n\
    " % prog
    sys.exit(-1)


def getOpts(argv):
    global logfile
    global verbose
    arg_list = 'l:v'
    try:
        optlist, args = getopt.getopt(argv[1:], arg_list)
        for opts in optlist:
            if ( opts[0] == "-l"):
                logfile = opts[1]
            if ( opts[0] == "-v"):
                verbose = 1
            if ( opts[0] == "-h"):
                usage(argv[0])
    except:
        raise
        print " [Message]: use %s -h" % argv[0]


def readCfg(fileCfg="./battepy.cfg"):
    cfg = {}
    try:
        cp = ConfigParser()
        cp.read(fileCfg)
        cfg["timeout"] = cp.getint("alerts", "banner_delay")
        cfg["sticky"] = cp.getint("alerts", "critical_sticky")
    except:
        raise

    return cfg


#
# battepy class
#
class battepy:

    __notification = None

    __imgPath = "./img"

    __statusSet = {
        "initial"       : (pynotify.URGENCY_NORMAL,     "b0.png"),
        "critical"      : (pynotify.URGENCY_CRITICAL,   "bcritical.png"),
        "charging"      : (pynotify.URGENCY_NORMAL,     "bcharging.png"),
        "discharging"   : (pynotify.URGENCY_CRITICAL,   "b0.png"),
        "5%"        : (pynotify.URGENCY_CRITICAL,   "b5.png"),
        "15%"       : (pynotify.URGENCY_CRITICAL,   "b15.png"),
        "30%"       : (pynotify.URGENCY_CRITICAL,   "b30.png"),
        "45%"       : (pynotify.URGENCY_NORMAL,     "b45.png"),
        "60%"       : (pynotify.URGENCY_NORMAL,     "b60.png"),
        "75%"       : (pynotify.URGENCY_NORMAL,     "b75.png"),
        "90%"       : (pynotify.URGENCY_LOW,        "b90.png"),
        "100%"      : (pynotify.URGENCY_LOW,        "b100.png"),
    }

    __battery = []


    def __init__(self, sleep=5, timeout=8, sticky=0):
        self.__sleep = sleep
        self.__timeout = timeout * 1000
        self.__sticky = sticky

        # supports 20 battery devices
        for batDev in range(1, 20):
            self.__battery.append( {
                "status"    : 0,
                "percent"   : 0,
                "discharg"  : 0,
                "remain"    : 0,
            } )


    def __message(self, status, timeout=1000):
        icon = gtk.gdk.pixbuf_new_from_file(self.__imgPath + "/" +
                self.__statusSet[status][1])

        pynotify.init("battepy")

        if ( status == "initial" ):
            string = "Initializing service"
            self.__notification = pynotify.Notification("battepy", string)
        else:
            self.__notification = pynotify.Notification("[Battery Status]",
                    " >>> " + status)
        
        self.__notification.set_icon_from_pixbuf(icon)
        self.__notification.set_urgency(self.__statusSet[status][0])
        self.__notification.set_timeout(timeout)
        self.__notification.show()


    def __getBatteryInfo(self):
        try:
            # all get all information to support online operations - add battery
            bus = dbus.SystemBus()

            hal_obj = bus.get_object('org.freedesktop.Hal',
                    '/org/freedesktop/Hal/Manager')
            
            hal = dbus.Interface (hal_obj, 'org.freedesktop.Hal.Manager')

            devs = hal.FindDeviceByCapability ('battery', 
                    dbus_interface='org.freedesktop.Hal.Manager')

            timeout = self.__timeout
            
            count = 0
            for dev in devs:
                batt = bus.get_object ('org.freedesktop.Hal', dev)

                iface = dbus.Interface (batt, 'org.freedesktop.Hal.Device')

                self.__battery[count]["percent"] = iface.GetProperty(
                        'battery.charge_level.percentage')

                if ( iface.GetProperty('battery.is_rechargeable') ):
                    discharging = iface.GetProperty(
                            'battery.rechargeable.is_discharging')
                    
                    # battery has changed its status
                    if ( self.__battery[count]["discharg"] == 0 and
                            discharging == 1 ):
                        status = "discharging"
                    elif ( self.__battery[count]["discharg"] == 1 and
                            discharging == 0 ):
                        status = "charging"
                    elif ( self.__battery[count]["percent"] < 5 ):
                        status = "critical"
                        if ( self.__sticky == 1 ):
                            timeout = 0
                    elif ( self.__battery[count]["percent"] >= 5 and 
                            self.__battery[count]["percent"] <= 15 ):
                        status = "5%"
                    elif ( self.__battery[count]["percent"] >= 15 and 
                            self.__battery[count]["percent"] <= 30 ):
                        status = "15%"
                    elif ( self.__battery[count]["percent"] >= 30 and 
                            self.__battery[count]["percent"] <= 45 ):
                        status = "30%"
                    elif ( self.__battery[count]["percent"] >= 45 and 
                            self.__battery[count]["percent"] <= 60 ):
                        status = "45%"
                    elif ( self.__battery[count]["percent"] >= 60 and 
                            self.__battery[count]["percent"] <= 75 ):
                        status = "60%"
                    elif ( self.__battery[count]["percent"] >= 75 and 
                            self.__battery[count]["percent"] <= 90 ):
                        status = "75%"
                    elif ( self.__battery[count]["percent"] >= 90 and 
                            self.__battery[count]["percent"] <= 98 ):
                        status = "90%"
                    else:
                        status = "100%"

                    self.__battery[count]["discharg"] = discharging

                if ( discharging ):
                    curr = iface.GetProperty('battery.charge_level.current')
                    desg = iface.GetProperty('battery.charge_level.rate')
                    # in seconds
                    self.__battery[count]["remain"] = curr / desg * 60 * 60

                # initializing service
                if ( self.__battery[count]["status"] == 0 ):
                    self.__message("initial")

                elif ( self.__battery[count]["status"] != status ):
                    if ( timeout is not None ):
                        self.__message(status, timeout)
                    else:    
                        self.__message(status)
                
                self.__battery[count]["status"] = status
                count += 1
        except:
            raise
            return -1


    def run(self):
        while ( 1 ):
            self.__getBatteryInfo()
            time.sleep(self.__sleep)



#
#  M  A  I  N
#
logfile = None
verbose = 0
logger    = None

if __name__ == "__main__":

    if ( sys.argv.__len__() < 2 ):
        usage(sys.argv[0])

    getOpts(sys.argv)

    logger = logging.getLogger("battepy")
    logger.setLevel(logging.DEBUG)
    if logfile:
        ch = logging.FileHandler(logfile)
    else:
        ch = logging.StreamHandler()
    ch.setLevel(logging.DEBUG)
    formatter = logging.Formatter("%(asctime)s - %(levelname)s - %(message)s")
    ch.setFormatter(formatter)
    logger.addHandler(ch)

    config = readCfg()
    if ( config is not None ):
        monitor = battepy(sleep=5, timeout=config['timeout'],
                sticky=config['sticky'])
    else:
        monitor = battepy(sleep=5)
    
    monitor.run()
